home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / net / res_send.c < prev    next >
C/C++ Source or Header  |  1988-07-29  |  8KB  |  369 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #if defined(LIBC_SCCS) && !defined(lint)
  14. static char sccsid[] = "@(#)res_send.c    6.20 (Berkeley) 5/19/88";
  15. #endif /* LIBC_SCCS and not lint */
  16.  
  17. /*
  18.  * Send query to name server and wait for reply.
  19.  */
  20.  
  21. #include <sys/param.h>
  22. #include <sys/time.h>
  23. #include <sys/socket.h>
  24. #include <sys/uio.h>
  25. #include <netinet/in.h>
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <arpa/nameser.h>
  29. #include <resolv.h>
  30.  
  31. extern int errno;
  32.  
  33. static int s = -1;    /* socket used for communications */
  34. static struct sockaddr no_addr;
  35.   
  36.  
  37. #ifndef FD_SET
  38. #define    NFDBITS        32
  39. #define    FD_SETSIZE    32
  40. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  41. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  42. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  43. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  44. #endif
  45.  
  46. #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
  47. #define BSD 43
  48.  
  49. res_send(buf, buflen, answer, anslen)
  50.     char *buf;
  51.     int buflen;
  52.     char *answer;
  53.     int anslen;
  54. {
  55.     register int n;
  56.     int retry, v_circuit, resplen, ns;
  57.     int gotsomewhere = 0, connected = 0;
  58.     u_short id, len;
  59.     char *cp;
  60.     fd_set dsmask;
  61.     struct timeval timeout;
  62.     HEADER *hp = (HEADER *) buf;
  63.     HEADER *anhp = (HEADER *) answer;
  64.     struct iovec iov[2];
  65.     int terrno = ETIMEDOUT;
  66.     char junk[512];
  67.  
  68. #ifdef DEBUG
  69.     if (_res.options & RES_DEBUG) {
  70.         printf("res_send()\n");
  71.         p_query(buf);
  72.     }
  73. #endif DEBUG
  74.     if (!(_res.options & RES_INIT))
  75.         if (res_init() == -1) {
  76.             return(-1);
  77.         }
  78.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  79.     id = hp->id;
  80.     /*
  81.      * Send request, RETRY times, or until successful
  82.      */
  83.     for (retry = _res.retry; retry > 0; retry--) {
  84.        for (ns = 0; ns < _res.nscount; ns++) {
  85. #ifdef DEBUG
  86.         if (_res.options & RES_DEBUG)
  87.             printf("Querying server (# %d) address = %s\n", ns+1,
  88.                   inet_ntoa(_res.nsaddr_list[ns].sin_addr));
  89. #endif DEBUG
  90.         if (v_circuit) {
  91.             int truncated = 0;
  92.  
  93.             /*
  94.              * Use virtual circuit.
  95.              */
  96.             if (s < 0) {
  97.                 s = socket(AF_INET, SOCK_STREAM, 0);
  98.                 if (s < 0) {
  99.                     terrno = errno;
  100. #ifdef DEBUG
  101.                     if (_res.options & RES_DEBUG)
  102.                         perror("socket failed");
  103. #endif DEBUG
  104.                     continue;
  105.                 }
  106.                 if (connect(s,
  107.                     (struct sockaddr *) &(_res.nsaddr_list[ns]),
  108.                     sizeof(struct sockaddr)) < 0) {
  109.                     terrno = errno;
  110. #ifdef DEBUG
  111.                     if (_res.options & RES_DEBUG)
  112.                         perror("connect failed");
  113. #endif DEBUG
  114.                     (void) close(s);
  115.                     s = -1;
  116.                     continue;
  117.                 }
  118.             }
  119.             /*
  120.              * Send length & message
  121.              */
  122.             len = htons((u_short)buflen);
  123.             iov[0].iov_base = (caddr_t)&len;
  124.             iov[0].iov_len = sizeof(len);
  125.             iov[1].iov_base = buf;
  126.             iov[1].iov_len = buflen;
  127.             if (writev(s, iov, 2) != sizeof(len) + buflen) {
  128.                 terrno = errno;
  129. #ifdef DEBUG
  130.                 if (_res.options & RES_DEBUG)
  131.                     perror("write failed");
  132. #endif DEBUG
  133.                 (void) close(s);
  134.                 s = -1;
  135.                 continue;
  136.             }
  137.             /*
  138.              * Receive length & response
  139.              */
  140.             cp = answer;
  141.             len = sizeof(short);
  142.             while (len != 0 &&
  143.                 (n = read(s, (char *)cp, (int)len)) > 0) {
  144.                 cp += n;
  145.                 len -= n;
  146.             }
  147.             if (n <= 0) {
  148.                 terrno = errno;
  149. #ifdef DEBUG
  150.                 if (_res.options & RES_DEBUG)
  151.                     perror("read failed");
  152. #endif DEBUG
  153.                 (void) close(s);
  154.                 s = -1;
  155.                 continue;
  156.             }
  157.             cp = answer;
  158.             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
  159. #ifdef DEBUG
  160.                 if (_res.options & RES_DEBUG)
  161.                     fprintf(stderr, "response truncated\n");
  162. #endif DEBUG
  163.                 len = anslen;
  164.                 truncated = 1;
  165.             } else
  166.                 len = resplen;
  167.             while (len != 0 &&
  168.                (n = read(s, (char *)cp, (int)len)) > 0) {
  169.                 cp += n;
  170.                 len -= n;
  171.             }
  172.             if (n <= 0) {
  173.                 terrno = errno;
  174. #ifdef DEBUG
  175.                 if (_res.options & RES_DEBUG)
  176.                     perror("read failed");
  177. #endif DEBUG
  178.                 (void) close(s);
  179.                 s = -1;
  180.                 continue;
  181.             }
  182.             if (truncated) {
  183.                 /*
  184.                  * Flush rest of answer
  185.                  * so connection stays in synch.
  186.                  */
  187.                 anhp->tc = 1;
  188.                 len = resplen - anslen;
  189.                 while (len != 0) {
  190.                     n = (len > sizeof(junk) ?
  191.                         sizeof(junk) : len);
  192.                     if ((n = read(s, junk, n)) > 0)
  193.                         len -= n;
  194.                     else
  195.                         break;
  196.                 }
  197.             }
  198.         } else {
  199.             /*
  200.              * Use datagrams.
  201.              */
  202.             if (s < 0)
  203.                 s = socket(AF_INET, SOCK_DGRAM, 0);
  204. #if    BSD >= 43
  205.             if (_res.nscount == 1 || retry == _res.retry) {
  206.                 /*
  207.                  * Don't use connect if we might
  208.                  * still receive a response
  209.                  * from another server.
  210.                  */
  211.                 if (connected == 0) {
  212.                     if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns],
  213.                         sizeof(struct sockaddr)) < 0) {
  214. #ifdef DEBUG
  215.                         if (_res.options & RES_DEBUG)
  216.                             perror("connect");
  217. #endif DEBUG
  218.                         continue;
  219.                     }
  220.                     connected = 1;
  221.                 }
  222.                 if (send(s, buf, buflen, 0) != buflen) {
  223. #ifdef DEBUG
  224.                     if (_res.options & RES_DEBUG)
  225.                         perror("send");
  226. #endif DEBUG
  227.                     continue;
  228.                 }
  229.             } else {
  230.                 /*
  231.                  * Disconnect if we want to listen
  232.                  * for responses from more than one server.
  233.                  */
  234.                 if (connected) {
  235.                     (void) connect(s, &no_addr,
  236.                         sizeof(no_addr));
  237.                     connected = 0;
  238.                 }
  239. #endif BSD
  240.                 if (sendto(s, buf, buflen, 0,
  241.                     (struct sockaddr *) &_res.nsaddr_list[ns],
  242.                     sizeof(struct sockaddr)) != buflen) {
  243. #ifdef DEBUG
  244.                     if (_res.options & RES_DEBUG)
  245.                         perror("sendto");
  246. #endif DEBUG
  247.                     continue;
  248.                 }
  249. #if    BSD >= 43
  250.             }
  251. #endif
  252.  
  253.             /*
  254.              * Wait for reply
  255.              */
  256.             timeout.tv_sec = (_res.retrans << (_res.retry - retry))
  257.                 / _res.nscount;
  258.             if (timeout.tv_sec <= 0)
  259.                 timeout.tv_sec = 1;
  260.             timeout.tv_usec = 0;
  261. wait:
  262.             FD_ZERO(&dsmask);
  263.             FD_SET(s, &dsmask);
  264.             n = select(s+1, (int *) &dsmask, (int *) NULL,
  265.                 (int *) NULL, &timeout);
  266.             if (n < 0) {
  267. #ifdef DEBUG
  268.                 if (_res.options & RES_DEBUG)
  269.                     perror("select");
  270. #endif DEBUG
  271.                 continue;
  272.             }
  273.             if (n == 0) {
  274.                 /*
  275.                  * timeout
  276.                  */
  277. #ifdef DEBUG
  278.                 if (_res.options & RES_DEBUG)
  279.                     printf("timeout\n");
  280. #endif DEBUG
  281.                 gotsomewhere = 1;
  282.                 continue;
  283.             }
  284.             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
  285. #ifdef DEBUG
  286.                 if (_res.options & RES_DEBUG)
  287.                     perror("recvfrom");
  288. #endif DEBUG
  289.                 continue;
  290.             }
  291.             gotsomewhere = 1;
  292.             if (id != anhp->id) {
  293.                 /*
  294.                  * response from old query, ignore it
  295.                  */
  296. #ifdef DEBUG
  297.                 if (_res.options & RES_DEBUG) {
  298.                     printf("old answer:\n");
  299.                     p_query(answer);
  300.                 }
  301. #endif DEBUG
  302.                 goto wait;
  303.             }
  304.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  305.                 /*
  306.                  * get rest of answer
  307.                  */
  308. #ifdef DEBUG
  309.                 if (_res.options & RES_DEBUG)
  310.                     printf("truncated answer\n");
  311. #endif DEBUG
  312.                 (void) close(s);
  313.                 s = -1;
  314.                 /*
  315.                  * retry decremented on continue
  316.                  * to desired starting value
  317.                  */
  318.                 retry = _res.retry + 1;
  319.                 v_circuit = 1;
  320.                 continue;
  321.             }
  322.         }
  323. #ifdef DEBUG
  324.         if (_res.options & RES_DEBUG) {
  325.             printf("got answer:\n");
  326.             p_query(answer);
  327.         }
  328. #endif DEBUG
  329.         /*
  330.          * We are going to assume that the first server is preferred
  331.          * over the rest (i.e. it is on the local machine) and only
  332.          * keep that one open.
  333.          */
  334.         if ((_res.options & KEEPOPEN) == 0 || ns != 0) {
  335.             (void) close(s);
  336.             s = -1;
  337.         }
  338.         return (resplen);
  339.        }
  340.     }
  341.     if (s >= 0) {
  342.         (void) close(s);
  343.         s = -1;
  344.     }
  345.     if (v_circuit == 0)
  346.         if (gotsomewhere == 0)
  347.             errno = ECONNREFUSED;
  348.         else
  349.             errno = ETIMEDOUT;
  350.     else
  351.         errno = terrno;
  352.     return (-1);
  353. }
  354.  
  355. /*
  356.  * This routine is for closing the socket if a virtual circuit is used and
  357.  * the program wants to close it.  This provides support for endhostent()
  358.  * which expects to close the socket.
  359.  *
  360.  * This routine is not expected to be user visible.
  361.  */
  362. _res_close()
  363. {
  364.     if (s != -1) {
  365.         (void) close(s);
  366.         s = -1;
  367.     }
  368. }
  369.